import cv2
import remi
import mmkv
import sys
import numpy as np
from cvs import *
import aidlite_gpu
#引用模块介绍
#cv2模块是OpenCV 2.0的简写，在计算机视觉项目的开发中，OpenCV作为较大众的开源库，拥有了丰富的常用图像处理函数库，采用C/C++语言编写，可以运行在Linux/Windows/Mac等操作系统上，能够快速的实现一些图像处理和识别的任务。
#remi是一个用于python应用程序的gui库，它将应用程序的接口转换成html并在web浏览器中呈现。这消除了特定于平台的依赖关系，使用户可以轻松地在python中开发跨平台应用程序
#sys模块包括了一组非常实用的服务，内含很多函数方法和变量，用来处理Python运行时配置以及资源，从而可以与前当程序之外的系统环境交互。 
#NumPy(Numerical Python) 是 Python 语言的一个扩展程序库，支持大量的维度数组与矩阵运算，此外也针对数组运算提供大量的数学函数库。在机器学习算法中大部分都是调用Numpy库来完成基础数值计算的。
#cvs图形控件模块
#tflite_gpu，GPU加速代码由AID提供，TensorFlow Lite 支持多种硬件加速器。
# GPU 是设计用来完成高吞吐量的大规模并行工作的。因此，它们非常适合用在包含大量运算符的神经网络上，
# 一些输入张量可以容易的被划分为更小的工作负载且可以同时执行，通常这会导致更低的延迟。
# 在最佳情况下，用 GPU 在实时应用程序上做推理运算已经可以运行的足够快，而这在以前是不可能的。

aidlite=aidlite_gpu.aidlite()

#图像与蒙板之间的转化（搬迁）
def transfer(image, mask):

    #将mask的像素矩阵（在python中是一个二维数组）改成与image同行数同列数
    mask = cv2.resize(mask, (image.shape[1], image.shape[0]))

    #np.zeros_like函数主要是想实现构造一个矩阵mask_n，其维度与矩阵image一致
    #并为其初始化为全0
    #这个函数方便的构造了新矩阵，无需参数指定shape大小
    mask_n = np.zeros_like(image)

    #将mask的值赋给mask_n的RGB值的0通道，也就是蓝色通道
    #mask_n[:, :, 0] = mask

    #绿色通道，效果不如蓝色通道
    #mask_n[:, :, 1] = mask

    #红色通道
    mask_n[:, :, 2] = mask

    alpha = 0.7 
     
    #beta = (1.0 - alpha)

    beta = (1.0 - alpha)

    #cv2.addWeighted是Python-OpenCV图像叠加or图像混合加权方法
    #其中image是第一个输入的数列
    #alpha是第一个数列诸元素的权重
    #mask_n是一个输入数列，它的大小和通道数与image必须相同
    #beta即第二个数列诸元素的权重
    #0.0处填入一个标量，需要加到每一个和值上
    dst = cv2.addWeighted(image, alpha, mask_n, beta, 0.0)
    # dst = cv2.addWeighted(image, alpha, mask_n, beta, 10.0)

    # # 分割rgb通道
    # b_channel, g_channel, r_channel = cv2.split(dst)
    # #  使用cv2.threshold函数，输入BRG三个通道的灰度图像，和触发阈值，和转换值，还有触发器类型
    # ret1,b = cv2.threshold(b_channel,1,139,cv2.THRESH_BINARY)
    # ret2,g = cv2.threshold(g_channel,1,5,cv2.THRESH_BINARY)
    # ret3,r = cv2.threshold(r_channel,1,139,cv2.THRESH_BINARY)

    # dst = cv2.merge((r,g,b))
    
    return dst

#宽高各512
w=512
h=512

#输入形状
input_shape=[w,h]

#语义：[一副图像*（512*512）像素*rgb加上alpha共四通道*4字节]
inShape =[1 * w * h *4*4,]

#语义：[一副图像*（512*512）像素*二通道*4字节]
outShape= [1 * w*h*2*4,]

#指定模型路径
model_path="models/hair_segmentation.tflite"
#参数语义：4代表四个通道、0代表使用GPU
print('gpu:',aidlite.ANNModel(model_path,inShape,outShape,4,0))

#指定一个摄像机ID，并捕捉该摄像机的视频流
#cvs.VideoCapture(1)是调用手机前置摄像头，如果是cvs.VideoCapture(0)就是调用手机后置摄像头。
camid=1
cap=cvs.VideoCapture(camid)

#np.zeros是np包的置零方法，用于给一个n维数组（在tensorflow中称为张量）初始化为全0
#(512,512,4)是三个维度的长度，表示512*512像素，4通道（RGB、透明通道）。
#dtype=np.float32设置元素类型为32位浮点型。
in_tensor = np.zeros((512,512,4),dtype=np.float32) 
masa = np.zeros((512,512),dtype=np.float32)

while True:
    
    #读取摄像头画面到帧
    frame=cap.read()

    #直到读取到摄像头的图像为止
    if frame is None:
        continue

    #flip()的作用是使图像进行翻转，cv2.flip(filename, flipcode) 
    #filename：需要操作的图像，flipcode：翻转方式，1水平翻转，0垂直翻转，-1水平垂直翻转
    #如果是前置摄像头，需要翻转图片，想象照镜子的原理
    if camid==1:
        # frame=cv2.resize(frame,(720,1080))
        frame=cv2.flip(frame,1)
    
    #改变img为与读取到的帧同大小
    img =cv2.resize(frame,(input_shape[0],input_shape[1]))

    #cv2.cvtColor(p1,p2) 是颜色空间转换函数，p1是需要转换的图片，p2是转换成何种格式。
    #cv2.COLOR_BGR2RGB 将BGR格式转换成RGB格式（蓝绿红到红绿蓝）  
    #cv2.COLOR_BGR2GRAY 将BGR格式转换成灰度图片
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    # print("image:", img)
    #img = (img / 255-0.5)*2

    # img读入Python后都是RGB值数组从0~255归一化至0~1
    img = img / 255
    
    
    in_tensor[:,:,0:3] = img
    in_tensor[:,:,3] = masa
    # in_tensor[:,:,0:3] = img_pre
    
    # print ('img',img.shape)

    
    # interpreter.set_tensor(input_details[0]['index'], img[np.newaxis,:,:,:])
    #此处也采用Fp32(三十二位浮点)，512*512像素
    aidlite.setTensor_Fp32(in_tensor,input_shape[1],input_shape[1])

    #设置启动时间
    start_time = time.time()

    #启动网络
    aidlite.invoke()
    
    t = (time.time() - start_time)
    # print('elapsed_ms invoke:',t*1000)
    #标签
    lbs = 'Fps: '+ str(int(1/t))+" ~~ Time:"+str(t*1000) +"ms"
    cvs.setLbs(lbs)    
    
    #pred变量存放张量组
    pred = aidlite.getTensor_Fp32(0)
    
    #pre0：前景（人脸）
    #变为512*512像素
    pred0=(pred[0::2 ]).reshape(w,h)
    #pred1：背景（头发）
    #变为512*512像素
    pred1=(pred[1::2]).reshape(w,h)
    #前景（人脸）复制到back
    back=((pred0)).copy()
    #背景（头发）复制到front
    front=((pred1)).copy()
    

    #求差值，赋给遮罩变量（前景减去背景）
    mask=front-back
    #print (list(mask))
    #print (mask)

    #此处可视为对mask的值进行二值逻辑化
    #将正值全部归纳至255，负值全部归纳为0
    mask[mask>0.0]=255
    mask[mask<0.0]=0
    #masa是mask单位化（将取值缩放到0~1）后的变量
    masa=mask/255

    mask_red = front-back
    print(mask_red.shape)
    # mask=masa
    # mask=cv2.merge([mask,mask,mask])
    # frame = cv2.resize(frame, (512,512))
    dst=transfer(frame,mask)
    
    # dst=(mask*128)+(1-mask)*frame

    #cvs.imshow(mask)
    #显示图像
    cvs.imshow(dst)

    #调用sleep()函数让当前线程暂停1s
    sleep(1)